package org.triumphxx.connpool.pool;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.Properties;

/**
 * @author:triumphxx
 * @Date:2022/5/21
 * @Time:10:17
 * @微信公众号：北漂码农有话说
 * @网站：https://blog.triumphxx.com.cn
 * @GitHub https://github.com/triumphxx
 * @Desc: 连接池对象
 **/
@Slf4j
public class ConnectionPool {
    //驱动
    private static String driverClass;
    //Url
    private static String url;
    //用户名
    private static String userName;
    //密码
    private static String password;
    //初始化连接数
    private static int initCount = 5;
    //最小连接数
    private static int minCount = 5;
    //最大连接数据
    private static  int maxCount =20;
    //已经创建的连接数据量
    private static  int createdCount;
    //连接增长步长
    private static int incCount = 2;
    //保存连接集合
    private LinkedList<Connection> conns = new LinkedList<>();
    //属性初始化
    static {
        Properties properties = new Properties();
        InputStream in = ConnectionPool.class.getClassLoader().getResourceAsStream("db.properties");
        try {
            properties.load(in);
            driverClass = properties.getProperty("jdbc.driverClass");
            url = properties.getProperty("jdbc.url");
            userName = properties.getProperty("jdbc.username");
            password = properties.getProperty("jdbc.password");
            //以下参数没有进行配置的话就获取默认值
            incCount = Integer.parseInt(properties.getProperty("jdbc.initCount"));
            minCount = Integer.parseInt(properties.getProperty("jdbc.minCount"));
            maxCount = Integer.parseInt(properties.getProperty("jdbc.maxCount"));
            incCount = Integer.parseInt(properties.getProperty("jdbc.incCount"));
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    //连接池对象  使用单例模式初始化
    private static volatile ConnectionPool instance;
    private ConnectionPool(){
        if (instance != null){
            throw new RuntimeException("此数据库连接池对象已经创建完成");
        }
        //初始化连接池
        init();
    }
    //获取连接池
    public static ConnectionPool getInstance(){
        //双重检查
        if (null == instance){
            synchronized (ConnectionPool.class){
                if (null == instance){
                    instance = new ConnectionPool();
                }
            }
        }
        return instance;
    }
   //初始化连接
    private void init(){
        for (int i = 0; i < initCount; i++) {
            boolean flag = conns.add(createConn());
            if (flag){
                createdCount ++;
            }
        }
        log.info("初始化数据库连接池完成");
        log.info("目前可用的连接数量为：{}",createdCount);
    }
    //创建连接对象
    private Connection createConn() {
        try {
            Class.forName(driverClass);
            return DriverManager.getConnection(url,userName,password);
        }catch (Exception e){
            throw new RuntimeException("数据库连接创建失败："+ e.getMessage());
        }
    }
    //数据库连接自动增长
    private synchronized void autoAdd(){
        if (createdCount == maxCount){
            throw new RuntimeException("连接池中连接数据量已经达到最大，无法再次创建连接");
        }
        //判断增长个数
        for (int i = 0; i < incCount; i++) {
            if (createdCount == maxCount){
                break;
            }
            conns.add(createConn());
            createdCount ++ ;
        }
    }
    //获取连接池中的连接
    public  Connection getConnection(){
        //判断池中是否有连接
        if (conns.size() > 0){
            conns.removeFirst();
        }
        //若没有空连接，调用自动增长方法
        if (createdCount < maxCount){
            autoAdd();
            return getConnection();
        }
        //若连接池中的连接数据量达到上线，等待连接归还
        log.error("连接池中的连接已经达到上限，请等待连接归还");
        try {
            Thread.sleep(3000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        return getConnection();

    }
    //自动减少连接
    private synchronized void autoReduce(){
        if (createdCount > minCount && conns.size() >0){
            //关闭空闲的连接
            try {
                conns.removeFirst().close();
                createdCount -- ;
            }catch (SQLException throwables) {
                throwables.printStackTrace();
            }

        }
    }
    //归还连接
    public void reConnection(Connection conn){
        log.info("归还数据库连接");
        conns.add(conn);
        //归还之后，减少连接
        autoReduce();
    }
    //返还可用连接数据量
    public int getCreatedCount(){
        return createdCount;
    }
}
